/**********************************************************************
* The hardware INdependent skeletons for the hardware dependent
* low level routines. This file is included by the file spr_low.c
* once for each different graphics card.
**********************************************************************
                    This file is part of

          STK -- The sprite toolkit -- version 1.0

              Copyright (C) Jari Karjala 1990

The sprite toolkit (STK) is a FreeWare toolkit for creating high
resolution sprite graphics with PCompatible hardware. This toolkit 
is provided as is without any warranty or such thing. See the file
COPYING for further information.

**********************************************************************/


/**********************************************************************
* ADDR
* Return the address of the given (x,y) coordinate pair in the
* given graphics page.
* 
* x,y     X,Y coordinates
* page    The graphics page (0/1)
*
* Return: far pointer into the screen.
**********************************************************************/
BYTE far *ADDR(WORD x, WORD y, BYTE page)
{
    return (BYTE far *)MK_FP(SCR_SEG+page*SCR_PAGE_2_SEG, SCR_OFS(x,y));
}


/**********************************************************************
* PUT
* Put the given shape into the given address using the given mask and
* saving the old contents into the given buffer. The shape and mask
* data must be combined as described in the file sprP.h and they
* must reside in the same segment as save buffer.
* 
* w       The width of the shape in bytes
* h       The height of the shape in pixels
* dest    The destination address in the frame buffer
* shape   The address of the combined shape/mask data
* save    The address of the save buffer
**********************************************************************/
void PUT(WORD w, WORD h, BYTE far *dest, BYTE far *shape, BYTE far *save)
{
#ifdef C_VER
    
    WORD i;
    BYTE tmp;

    while (h-- > 0) {
        for (i=0; i<w; i++, shape++, shape++, dest++, save++) {
            tmp = *dest;
            *dest = (tmp & *(shape+1)) | *shape;
            *save = tmp;
        }
        NEXT_SCAN_LINE(dest, w);
    }
    
#else
/***** Assembler version is about 2 to 3 times faster *****/
asm push ds
asm push es
asm cld
    /** fetch parameters **/
asm mov  ax, w
asm mov  dl, al         /** use only low byte of width! **/
asm mov  ax, h
asm mov  dh, al         /** use only low byte of height! **/
asm les  di, dest
asm lds  si, shape      /** shape and save must point into same segment **/
asm lds  bx, save
    /** dh=height, dl=width, es:di=dest, ds:si=shape, ds:bx=save **/
HEIGHT_LOOP:
asm mov  cl, dl
asm push di
WIDTH_LOOP:
asm lodsw            /** now we have shape byte in al and mask byte in ah **/
asm mov  ch, es:[di] /** take byte from screen **/
asm mov  [bx], ch    /**  save it **/
asm and  ch, ah      /**  and it with mask **/
asm or   al, ch      /**  or the shape **/
asm stosb            /**  and store back **/
asm inc  bx          /** next byte in save buffer **/
asm dec  cl          /** decrement width counter and jump back if not zero **/
asm jnz  WIDTH_LOOP
asm pop  di
    /** advance to next scanline **/
ASM_NEXT_SCAN_LINE(di)
asm dec  dh          /** decrement height counter and jump back if not zero */
asm jnz  HEIGHT_LOOP
asm pop  es
asm pop  ds

#endif

}

/**********************************************************************
* XOR_PUT
* Put the given shape into the given address using the XOR method.
* The shape and mask
* data must be combined as described in the file sprP.h and they
* must reside in the same segment as save buffer.
* 
* w       The width of the shape in bytes
* h       The height of the shape in pixels
* dest    The destination address in the frame buffer
* shape   The address of the combined shape/mask data
* save    The address of the save buffer	(NOT USED)
**********************************************************************/
void XOR_PUT(WORD w, WORD h, BYTE far *dest, BYTE far *shape, BYTE far *save)
{
#ifdef C_VER
    
    WORD i;
    BYTE tmp;

    while (h-- > 0) {
        for (i=0; i<w; i++, shape++, shape++, dest++)
            *dest ^= *shape;
        NEXT_SCAN_LINE(dest, w);
    }
    
#else
/***** Assembler version is about 2 to 3 times faster *****/
asm push ds
asm push es
asm cld
    /** fetch parameters **/
asm mov  ax, w
asm mov  dl, al         /** use only low byte of width! **/
asm mov  ax, h
asm mov  dh, al         /** use only low byte of height! **/
asm les  di, dest
asm lds  si, shape
    /** dh=height, dl=width, es:di=dest, ds:si=shape **/
HEIGHT_LOOP:
asm mov  cl, dl
asm push di
WIDTH_LOOP:
asm lodsw            /** now we have shape byte in al and mask byte in ah **/
asm xor  es:[di], al /** take byte from screen **/
asm inc  di          /** next byte in screen **/
asm dec  cl          /** decrement width counter and jump back if not zero **/
asm jnz  WIDTH_LOOP
asm pop  di
    /** advance to next scanline **/
ASM_NEXT_SCAN_LINE(di)
asm dec  dh          /** decrement height counter and jump back if not zero */
asm jnz  HEIGHT_LOOP
asm pop  es
asm pop  ds

#endif

}


/**********************************************************************
* ERASE
* Erase the sprite from screen by putting the saved data back
* 
* dest    The destination address in the frame buffer
* save    The address of the save buffer
* w       The width of the shape in bytes
* h       The height of the shape in pixels
**********************************************************************/
void ERASE(WORD w, WORD h, BYTE far *dest, BYTE far *save)
{
#ifdef C_VER
    WORD i;

    while (h-- > 0) {
        for (i=0; i<w; i++, dest++, save++)
            *dest = *save;
        NEXT_SCAN_LINE(dest, w);
    }
#else
/***** Assembler version is about 2 to 3 times faster *****/
asm push ds
asm push es
asm cld
    /** fetch parameters **/
asm mov  ax, w
asm mov  dl, al         /** use only low byte of width! **/
asm mov  ax, h
asm mov  dh, al         /** use only low byte of height! **/
asm les  di, dest
asm lds  si, save
    /** dh=height, dl=width, es:di=dest, ds:si=shape, ds:bx=save **/
HEIGHT_LOOP:
asm mov  cl, dl
asm mov  ch, 0
asm push di
WIDTH_LOOP:
asm rep movsb          /** restore one scanline **/
asm pop  di
    /** advance to next scanline **/
ASM_NEXT_SCAN_LINE(di)
asm dec  dh          /** decrement height counter and jump back if not zero */
asm jnz  HEIGHT_LOOP
asm pop  es
asm pop  ds

#endif
}

/** Undefine hardware dependent macros to make later redefinition easier **/

#undef ADDR
#undef PUT
#undef XOR_PUT
#undef ERASE
#undef NEXT_SCAN_LINE
#undef ASM_NEXT_SCAN_LINE
#undef SCR_OFS
#undef SCR_SEG
#undef SCR_PAGE_2_SEG
